React Hook 是 React 16.8 中新增的功能,它解決了以下幾個問題:
class 也能使用 state 和 React 其他的功能,使得 function component 能更有效的被使用。DOM 等行為,都會產生 side effect(副作用)。在 class component 中,我們透過 componentDidMount、componentDidUpdate、componentWillUnmount 這幾個方法來處理 side effect。透過 React Hook,我們在 function component 中只要利用一個叫 useEffect 的方法即可處理,更為簡便易用。useReducer、useContext 功能做處理。class 在學習及使用上都更為複雜,class component 對於目前的一些開發工具來說也不好壓縮。useState 能讓 function component 使用 state,下面是它的一個基本使用方式。useState 中有一個參數initState,是初始的 state。initState可以是任意類型的值,也可以是一個回調函式,但必須有返回值。我們調用 useState 後會返回一個陣列,陣列內的兩個值 state 是我們要設置的狀態,setState 是更新陣列內 state 的函式。
const [state, setState] = useState(initState)
下面為一個簡單的加數字功能範例,我們使用 useState 來設定 state、更新方法及初始值,透過 onClick 觸發 setCount 去改變 state。
// 引用 useEffect
import { useState } from 'react';
const Test = () => {
// 設定 state、更新方法及初始值
const [count, setCount] = useState(0)
return <div>
<div>{ count }</div>
<div><button onClick={ () => setCount(count + 1) }>click</button></div>
</div>
}
useEffect 如前面所述,是用來處理 side effect 用的,也是 componentDidMount、componentDidUpdate、componentWillUnmount 三個函式的統一。它接受兩個參數,callback 和 array,callback 是我們處理 side effect 的回調函式,array是決定 useEffect 的執行。useEffect 是在元件第一次 render 和每次 render 時會執行
所有的 side effect 行為都應該在 useEffect 裡面處理,另外也可以透過返回一個函式來進行清理,如下面的 return,它會在元件卸載時候自動調用,相當於 class component 的 componentWillUnmount。
useEffect(() => {
// side effect
return () => {
// 清理工作,類似 componentWillUnmount
}
})
array 參數控制 useEffect 的執行,如果是空陣列,就只會在元件第一次 render 後執行,相當於 componentDidMount,如果陣列內有值,那會在陣列內的值發生改變後執行。還有一種情況是沒有 array 參數,那 useEffect 就會在每一次 render 後都執行一次。陣列內的值可以是元件內的 state,或是元件外傳入的 props。
useEffect(() => {
// side effect
}, []) // 第一次 render 時,執行一次
useEffect(() => {
// side effect
}, [count]) // 陣列內的值發生變化時執行
useEffect(() => {
// side effect
}) // 每次次 render 時,都執行一次
下面的範例中,count 每次發生改變,useEffect 都會執行一次。
import { useState, useEffect } from 'react';
const Test = () => {
// 設定 state、更新方法及初始值
const [count, setCount] = useState(0)
useEffect(() => {
//手動修改 react dom
document.title = `點擊了${count}次`
}, [count])// count 每次改變,useEffect 都會執行一次
return <div>
<div>{ count }</div>
<div><button onClick={ () => setCount(count + 1) }>click</button></div>
</div>
}
我們也可以同時使用多個 useEffect,以下面的範例來說,我們就可以決定在不同時間點渲染時,去執行不同的事情。
const Test = () => {
// 設定 state、更新方法及初始值
const [count, setCount] = useState(0
useEffect(() => {
document.title = `還沒點擊`
}, [])// 第一次 render 時執行
useEffect(() => {
// side effect
document.title = `點擊了${count}次`
}, [count]) // count 每次改變,useEffect 都會執行
return <div>
<div>{ count }</div>
<div><button onClick={ () => setCount(count + 1) }>click</button></div>
</div>
}
我們也可以在 useEffect 進行遠端資料請求,如下面利用空陣列,在第一次 render 時請求資料
const Test = () => {
// 設定 state、更新方法及初始值
const [data, setData] = useState(0
const fetchData = async () => {
const result = await fetch('./user.json').then(res => res.json())
setData()
}
useEffect(() => {
//手動修改 react dom
fetchData()
}, [])// count 每次改變,useEffect 都會執行一次
return <div>
<div>{ data }</div>
</div>
}
React 中有兩種常見的 side effect 類型,一種需要清理,一種不需要,如下
useEffect 會在每次執行之前,自動清理之前的 side effect。